#pragma once
#include "InOut.h"

namespace ExperientialSystem
{
	class DecisionTree;
	class IStatus;
}

class WinnerChecker;
class Point;
class ChessStatus;

typedef void* SimpleFun();
typedef bool* BoolFun();

class _EXPORT ChessTree
{
	ExperientialSystem::DecisionTree *_tree;

	SimpleFun *_onStart;
	SimpleFun *_onEpoch;
	BoolFun *_checkEnd;

	const int ADD_STATUS_DEPTH = 3;
	const double WIN_RATE_DISCOUNT = 0.8;
	const int SEARCH_NEXT_DEPTH = 3;

	friend class ChessTrainer;

public:
	ChessTree(const std::string treePath, WinnerChecker* winnerChecker);
	ChessTree(WinnerChecker* winnerChecker);
	~ChessTree();

	void UpdateValue(shared_ptr<ExperientialSystem::IStatus> status);

	Point NextPoint(shared_ptr<ExperientialSystem::IStatus> status);

	void StartTraining();

	void SetCallBacks(SimpleFun onStart, SimpleFun onEpoch, BoolFun checkEnd)
	{
		_onStart = onStart;
		_onEpoch = onEpoch;
		_checkEnd = checkEnd;
	}

private:

	void TryAddNextStatus(shared_ptr<ChessStatus> status, int depth);

	ChessStatus* ComputeOptimalStatus(shared_ptr<ExperientialSystem::IStatus> status);

	bool ComputeOptimalValue(const ChessStatus* curStatus, const int curDepth, double& optimalValue);
};

